import { createAsyncThunk, createSlice, isRejected } from "@reduxjs/toolkit";
import { getRequest, putRequest } from "../util/Net";
import { RootState } from "./store";
import { Gender, int } from "../types";

// 1. Requests.

interface UpdateProfileRequest {
  name: string;
  gender: int;
}

interface ResetPasswordRequest {
  password: string;
}

// 2. Responses.

interface PersonalInformationResponse {
  uid: int;
  userName: string;
  name: string;
  gender: int;
  roleName: string;
}

// 3. Params for reducers.

interface UpdateProfileParams {
  name: string;
  gender: Gender;
}

interface ResetPasswordParams {
  password: string;
}

// 4. State and initial value definition.

interface PersonalInformationState {
  loaded: boolean;
  passwordUpdated: boolean;
  profileUpdated: boolean;
  uid: int;
  userName: string;
  name: string;
  gender: Gender;
  role: string;
}

const initialState: PersonalInformationState = {
  loaded: false,
  passwordUpdated: false,
  profileUpdated: false,
  uid: 0,
  userName: '',
  name: '',
  gender: Gender.Unknown,
  role: ''
};

// 5. Async functions definition.

const getProfile = createAsyncThunk('/profile/get', async () => {
  const response = await getRequest<PersonalInformationResponse>({
    url: '/profile'
  });
  return response.data;
});

const updateProfile = createAsyncThunk('/profile/put', async (params: UpdateProfileParams) => {
  const response = await putRequest<null, UpdateProfileRequest>({
    url: '/profile',
    request: {
      name: params.name,
      gender: params.gender
    }
  });
  return response.data;
});

const updatePassword = createAsyncThunk('/profile/password/put', async (params: ResetPasswordParams) => {
  const response = await putRequest<null, ResetPasswordRequest>({
    url: '/account/password',
    request: {
      password: params.password
    }
  });
  return response.data;
});

// 6. Slice definition.

const personalInformationSlice = createSlice({
  name: 'personalInformation',
  initialState: initialState,
  reducers: {
    clear: (state) => {
      state.loaded = false;
      state.uid = 0;
      state.userName = '';
      state.name = '';
      state.gender = Gender.Unknown;
      state.role = '';
      state.passwordUpdated = false;
      state.profileUpdated = false;
    },
    clearPasswordUpdated: (state) => {
      state.passwordUpdated = false;
    },
    clearProfileUpdated: (state) => {
      state.profileUpdated = false;
    }
  },
  extraReducers: (builder) => {
    builder.addCase(getProfile.fulfilled, (state, action) => {
      const result = action.payload.result;
      state.uid = result.uid;
      state.userName = result.userName;
      state.name = result.name;
      state.gender = result.gender;
      state.role = result.roleName;
      state.loaded = true;
    }).addCase(updateProfile.fulfilled, (state, action) => {
      state.profileUpdated = true;
      state.loaded = false;
    }).addCase(updatePassword.fulfilled, (state, action) => {
      state.passwordUpdated = true;
    }).addMatcher(isRejected, (state, action) => {
      console.error(action.error);
    });
  }
});

export default personalInformationSlice.reducer;
export const profileActions = { ...personalInformationSlice.actions, getProfile, updateProfile, updatePassword };
export const selectProfileLoaded = (root: RootState) => root.profileReducer.loaded;
export const selectUid = (root: RootState) => root.profileReducer.uid;
export const selectUserName = (root: RootState) => root.profileReducer.userName;
export const selectName = (root: RootState) => root.profileReducer.name;
export const selectGender = (root: RootState) => root.profileReducer.gender;
export const selectRole = (root: RootState) => root.profileReducer.role;
export const selectPasswordUpdated = (root: RootState) => root.profileReducer.passwordUpdated;
export const selectProfileUpdated = (root: RootState) => root.profileReducer.profileUpdated;